﻿//【初阶】24.继承和多态
//【初阶】25.多态

//【头文件包含】
//C++的主要头文件
#include<iostream>//c++的输入输出流
using std::cout, std::endl, std::cin;

#include<stack>
#include<queue>
#include<string>
#include<deque>;
using std::deque;
using std::stack;
using std::queue;
using std::string;
//C的主要头文件
//#include<stdio.h>
//#include<stdlib.h>
//#include<assert.h>
//#include<string.h> 
#include<vector>;
using std::vector;
using std::priority_queue;




//【命名空间】

//【结构体声明】【类声明】
//继承
class Person
{
public:
	Person(const string& name="", const size_t& age=0) :_name(name), _age(age)
	{
		cout << "Person()" << endl;
	}
	Person(const Person& p)
	{
		_name = p._name;
		_age = p._age;
		cout << "Person(const Person&)" << endl;
	}
	void Print_Ifm()
		{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
		}
	virtual void BuyTicket() { cout << "买票-全价" << endl; }
	~Person()
	{
		cout << "~Person()" << endl;
	}
	string _name;
protected:
	size_t _age;
private:

};
/*派生类*/class Student :virtual public Person
{
public:
	Student(const string& name="", size_t age = 1, size_t stuid = 0)
		:Person(name,age) ,_stuid(stuid),_age(age)
	{
		cout << "Student()" << endl;
	}
	void Print_Ifm_Stu()
	{
		Print_Ifm();
		cout << "stuid:" << _stuid << endl;
		cout << "S_age:" << _age << endl;
		cout << "P_age:" << Person::_age << endl;
	}
	virtual void BuyTicket() { cout << "买票-半价" << endl; }
	~Student()
	{
		cout << "~Student" << endl;
	}
protected:
	size_t _stuid;
	size_t _age;
};
/*派生类*/struct Teacher : virtual Person
{
protected:
	int _jobid;
};
/*派生类*/class Assistant :public Student, public Teacher
{
public:
	Assistant()
	{}
protected:
};
void Func(Person& p)
{
	p.BuyTicket();
}

//虚继承
class A
{
public:
	int _a;
};
// class B : public A
class B : virtual public A
{
public:
	int _b;
};
// class C : public A
class C : virtual public A
{
public:
	int _c;
};
class D : public B, public C
{
public:
	int _d;
};

//【函数声明】
void Test1();void Test2();void Test3(); 


//【主函数】
int main()
{
	
	Test1();
	Test2();
	Test3();
    
	cout << "****主函数结束****" << endl;
	return 0;
}

/*测试用例*/void Test1()
{
	cout << "****测试用例开始****"<< endl;
	Student s("abc", 20, 2025);
	s.Print_Ifm();
	s.Print_Ifm_Stu();
	Teacher t;
	Assistant a;
	a._name = "aas";
	a.Student::_name = "ast";
	cout << a._name << endl;
	cout << a.Student::_name << endl;
	
	cout << "****测试用例结束****" << endl << endl;
}
/*测试用例*/void Test2()
{
	cout << "****测试用例开始****" << endl;
	D d;
	cout << sizeof(d) << endl;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
    d._a = 6;
	cout << "****测试用例结束****" << endl<<endl;
}

/*测试用例*/void Test3()
{
	cout << "****测试用例开始****" << endl;
	Person ps;
	Student st;

	Func(ps);
	Func(st);
	cout << "****测试用例结束****" << endl << endl;
}



//【笔记】
//【初阶】24.继承和多态
//面向对象有三大特性：封装、继承、多态，在更高版本的C++中还有抽象、反射 
//继承
	//派生类默认函数
		//在构造、析构等默认函数时属于基类的调用基类的默认函数，属于派生的调用自己的默认函数，
		// 即便是在初始化时强行初始化基类，也需要利用基类的构造函数进行初始化
		//派生类和基类同名的函数构成隐藏，派生类的析构函数和父类的析构函数构成隐藏
		//默认函数顺序大致为：
			//基类构造->派生类构造->派生类行为->派生类析构->基类析构 
		//友元关系不能被继承 
			//基类的友元不能访问派生类私有和保护
		// 静态成员继承
			//如果基类有一静态成员，那在整个继承体系内只有这唯一一个静态成员，不构成重定义，所有同名静态成员视为一个值
	//单继承/多继承/特殊
		// 只有一个基类是单继承、多个基类是多继承
		// 特殊的还有菱形继承，即一个基类有两个派生类，另外还有一个派生类继承上两个派生类
		// 多继承存在冗余和二义性，即歧义//虚继承 virtual可以解决该问题
		// 虚继承会生成虚基表指针用于定位属于该虚继承类的父类成员
		// 尽量避免多继承和菱形继承
	//继承和组合
		//继承和组合都可以实现类层次的复用
		// 继承是白箱复用，派生类is基类，基类内部对派生类可见，一定程度破坏了基类的封装
		// 组合是黑箱复用，组合类has被组合类，被组合类内部对组合类是不透明的，被包含的类封装性不变
//多态
	// 在完成某些行为是，不同对象会产生不同的状态
	// 构成多态的条件（必要）
		// 1.必须通过基类指针或引用调用虚函数
		// 2.调用的函数必须时虚函数，且在派生类内必须重写虚函数
	// 虚函数
		// 特殊的：继承类重写时不加virtual也构成虚函数重写
		// 通过在函数前增加关键组virtual实现，和虚继承是两个概念，但虚函数同样在创建时会产生一个虚基表指针
	// 重写
		// 构成函数重写指函数名、返回值类型、参数列表完全相同 
	//派生类对象本质上也是“基类”（指类型，不是对象），因为他包含基类的全部
	//个人理解	
		// 所以如果在实现多态时使用基类指针和引用调用虚函数是相当于传了一个特化的基类（指派生类）（切片）
		// 而派生类中通过重写创建了虚函数，所以在使用时通过虚基表查找到属于派生类的特化的虚函数去执行
	//多态的特殊情况：协变
		//虚函数重写时，返回值类型不同，返回值为基类返回基类对象指针、派生类返回派生类对象指针和引用
	//析构也可以实现虚函数，且有必要
		// 因为如果将一个派生类切片给一个基类指针，那么在析构该基类指针变量时，只会析构基类部分，可能导致内存泄露
	//虚函数缺省值
		// 在虚函数重写时如果基类的虚函数参数存在缺省值，那么后续的继承类虚函数的缺省会无效，只使用基类的缺省值
	//关键字final
		// 在虚函数后或虚继承后增加final则说明之后无法再被继承或重新
	//关键字override
		// 可以在派生类的虚函数后增加override，用于检查派生类的虚函数是否正确重写
	//函数的重载、重写（覆盖）、重定义（隐藏）
		//重载：同一作用域内，函数名相同、参数不同（返回值、参数列表、返回值类型任一）
		//重写：基类和派生类分别有同名同返回值同参数列表
		//重定义：基类和派生类分别有同名函数，不构成重写就是重定义
	//抽象类
		//包含纯虚函数的类（在函数后=0，不需要实现），抽象类不能实例化
		//作用
			// 利用纯虚函数强制子类必须重写
			// 表示抽象的类型

